StateX class topic
The State Class Extended
Extend the capabilities of Flutter’s own State class. This class allows you to use a State Object Controller (SOC) to reliably call the State object's setState() function from outside its class — a very powerful capability!
This class provides the initAsync() function to perform any asynchronous operations before displaying its contents. It also provides the dependOnInheritedWidget() function to assign a widget as a 'dependency' to the StateX's built-in InheritedWidget. It then uses its notifyClients() function to spontaneously rebuilt only those widgets. Very powerful!
Code | State Pattern | Sync | Sync | Interface? | Inherit |
- The State Object Controller separates the interface (i.e. the State object's build() function) from everything else: StateXController
- A function to perform any necessary asynchronous operations before displaying the interface: initAsync()
- A means to update only particular widgets in the interface and not the whole screen improving performance: dependOnInheritedWidget() , didChangeDependencies() , notifyClient() , setBuilder() , updateShouldNotify()
- A function that runs if any error occurs. Allows you to 'clean up' and fail gracefully: onError()
Control Your Code
All your ‘mutable’ code should go into your State Object Controller. It would contain the ‘business logic’ involved in a given app as well as address any event handling. Controllers are not new to Flutter. Two popular widgets that use a controller, for example, is the TextField widget and the SingleChildScrollView widget.However, unlike those two widgets, a StateX object can have any number of controllers. This promotes more modular development where each controller is dedicated to a particular responsibility independent of other controllers. This further relieves any 'controller bloat' common when involving a controller ( see State Object Controller).
State Pattern
A common pattern seen when implementing a controller for use by a StateX object will have the controller object instantiated right in the State object and then referenced here and there in the State object’s build() function. Thus providing the data and the event handling. For example, the first screenshot below is of the ' counter example app' that uses this package. The second screenshot shows how a number of controllers can be added.(A controller and its use are highlighted by red arrows.)
_MyHomePageState | Page1State |
---|
Sync The State
There's now a means to deal with asynchronous operations in the State object before rendering its interface. A common approach has been to execute such operations even before the app begins---a disjointed approach. The operation is not done by the actual State object (the actual screen) where it's relevant or required. However, Flutter has always had the FutureBuilder widget to make this possible. A FutureBuilder widget is built into the StateX class, and has its initAsync() function to then perform such asynchronous operations. As a result, when such a State object is called, it can wait for its asynchronous operations to complete before proceeding. As easy as that.
Below are three gif files. The first one depicts what a user will see more often than not when starting up an app written with this package. There's always a remote database to open or web services to connect to and this takes a little time. You don't want your user staring at a blank screen. They'll think the app is frozen! A spinner is displayed indicating the app is indeed running. The second gif file depicts twelve separate StateX objects waiting to continue. Each has its own individual asynchronous operation loading a animal graphic from some REST api somewhere. The last gif file shows the whole startup process for this particular app. It carry's on and shows you they are indeed individual operations ending with a different picture.
In this case, since they're running on an Android emulator, those spinners are from the CircularProgressIndicator widget. If they were running on an iOS phone, the CupertinoActivityIndicator widget would produce the iOS-style activity indicators instead. Flutter is a cross-platform SDK after all.image_api_controller.dart | working_memory_app.dart |
---|
Control The Sync
Those three screens above are from the example app supplied with this package. Yes, there are twelve separate StateX objects on that one screen each loading an animal image. Actually its their own individual State Object Controller that's performing the asynchronous download. Above, is a screenshot of that controller's own initAsync() function. While each controller is calling its _loadImage() function, its associated StateX object will quietly wait with its indicator spinning away on the screen. Very nice.
The screenshot on the right is another initAsync() function from another app altogether. It demonstrates there can be a number of asynchronous operations performed before an app can continue. This particular app involves the authentication of the user for example. If not already logged in a login screen will appear. This function is in another controller and that controller calls yet another controller to run its own initAsync(). See how you're able to separate distinct asynchronous operations each prefixed with an await operator and returning a boolean value to the variable, init. It's all easy to read and all in the right location to be implemented.
It's suggested you implement such operations in a Controller, and not directly in a StateX object. Besides, the StateX object's own initAsync() function is already implemented: It's calling all the initAsync() functions from its associated State Object Controllers. When they're all complete, only then does the StateX object call its build() function. Since most asynchronous operations have no direct relation to an app’s interface, you’ll likely have your asynchronous stuff running in a State Object Controller anyway with the rest of the app’s business logic. See how that works?
There can be individual controllers running their own initAsync() function. Very clean. Very modular.
Inherit The State
You've may have been introduced to the InheritedWidget, and how it allows you to repel down the widget tree any piece of data you've designated. However, a more intriguing feature is whenever you call an already instantiated InheritedWidget, any widgets assigned as its dependents are rebuilt (their build() functions run again)---as if their setState() functions were explicitly called.Now that allows for improved performance with the refresh of only specific areas of the interface.
Even the efficiency of the humble 'counter app' is greatly improved. Instead of refreshing the whole screen (including the StatelessWidget with its 'You have pushed the button this many times') , when the 'Use the built-in InheritedWidget' switch is on, only the lone widget displaying the current count is then ever rebuilt. The rest of the screen would now be left alone with every press of that button. Granted this is a very simple interface and possibly a bad example, but look how easy this is implemented in the screenshot below.counter_app.dart |
---|
The setBuilder() function found will allow for this immediate improvement in efficiency. When it comes to interfaces, the less that's rebuilt, the better.
Back to the app with its grid of animal pictures, you can see above when the 'new dogs' text button is pressed, only the three 'dog pictures' are downloaded again. What your seeing are only three portions of the screen being updated---only three widgets being rebuilt. If the whole screen was rebuilt, all the pictures would change. Not very effective.
counter_app.dart |
---|
The screenshot above depicts one of the three widgets being assigned as a dependent to a State object's InheritedWidget using the dependOnInheritedWidget() function. In fact, the State object's controller with its own dependOnInheritedWidget() function is actually used.
Classes
- AppStateMixin StateX class State Object Controller
- Supply access to the 'App' State object.
-
AppStateX<
T extends StatefulWidget> Get started StateX class AppStateX class - The StateX object at the 'app level.' Used to effect the whole app by being the first State object instantiated.
- ImplNotifyListenersChangeNotifier StateX class State Object Controller
- Implements the ChangeNotifier for both StateX ans StateXController
- RouteObserverStates StateX class State Object Controller
-
Makes every StateX and StateXController a RouteAware object
calling didPop, didPush,
didPopNext
anddidPushNext
Implemented by default. - StateDependentWidget StateX class AppStateX class
-
Used by the
setBuilder
function in both AppStateX and StateX Supply a widget to depend the built-in InheritedWidget -
StateX<
T extends StatefulWidget> Get started StateX class Using FutureBuilder Error handling Testing Event handling - An extension of Flutter's State class.
- StateXInheritedWidget StateX class
- The built-in InheritedWidget used by StateX
- StateXonErrorMixin StateX class Error handling
- Supply an 'error handler' routine if something goes wrong. It need not be implemented, but it's their for your consideration.
- Uuid StateX class State Object Controller
- Shamelessly extracted from the author of Scoped Model plugin, Who maybe took from the Flutter source code. I'm not telling!
- WidgetsBindingInstanceMixin StateX class State Object Controller
- Implements inWidgetsFlutterBinding and inFlutterTest for both StateX and StateXController
Mixins
- AsyncOps StateX class State Object Controller
- Supply the Async API to StateX and StateXController initAsync, initAsyncState and onAsyncError
- ErrorInErrorHandlerMixin StateX class Error handling
- Record errors in the Error Handler itself The developer has introduces an error in the handling itself. They must be notified. recordErrorInHandler, recErrorMsg, recErrorException, recStackTrace
- FutureBuilderStateMixin StateX class Using FutureBuilder
-
Supply the built-in FutureBuilder to the StateX object.
build is overwritten. See
Implementation
See: initAsync, onAsyncError and buildF - InheritedWidgetStateMixin StateX class
- Supplies the built-in InheritedWidget to a StateX class
- MapOfStateXsMixin StateX class
- Works with the collection of State objects in the App.
- RootStateMixin StateX class State Object Controller
- Deprecated, Use AppStateMixin mixin instead.
- StateXControllersByTypeMixin StateX class
- Collects Controllers of various types. A State object, by definition, then can't have multiple instances of the same type.
- StateXEventHandlers StateX class State Object Controller Event handling
- Supplies the event handling in all the StateXController and StateX objects.